package cn.jinbyte.web.utils;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Objects;

/**
 * 路径匹配工具类，用于判断请求路径是否需要排除安全检查
 * 支持Ant风格的路径模式：
 * - ? 匹配任意单个字符
 * - * 匹配任意数量的字符（不包括路径分隔符）
 * - ** 匹配任意数量的字符（包括路径分隔符）
 */
public class PathMatcherUtil {
    /**
     * 默认排除的url
     */
    public static final String[] DEFAULT_EXCLUDE_URL_PATTERNS = {
            "/error",
            "/webjars/**",
            "/swagger-ui.html",
            "/swagger-ui/**",
            "/swagger-resources/**",
            "/v3/api-docs/**",
            "/v2/api-docs/**",
            "/favicon.ico",
            "/**/*.html",
            "/**/*.css",
            "/**/*.js",
            "/**/*.png",
            "/**/*.jpg",
    };

    // 单例模式，确保全局使用同一个PathMatcher实例
    private static final AntPathMatcher pathMatcher = new AntPathMatcher();

    /**
     * 判断请求路径是否在排除列表中
     *
     * @param request      HTTP请求对象
     * @param excludePaths 排除路径列表（Ant风格模式）
     * @return 如果匹配返回true，否则返回false
     */
    public static boolean isExcluded(HttpServletRequest request, List<String> excludePaths) {
        Assert.notNull(request, "HttpServletRequest不能为null");

        if (excludePaths == null || excludePaths.isEmpty()) {
            return false;
        }

        String requestPath = getRequestPath(request);
        return isPathExcluded(requestPath, excludePaths);
    }

    /**
     * 判断指定路径是否在排除列表中
     *
     * @param path         要检查的路径
     * @param excludePaths 排除路径列表（Ant风格模式）
     * @return 如果匹配返回true，否则返回false
     */
    public static boolean isPathExcluded(String path, List<String> excludePaths) {
        Assert.hasText(path, "路径不能为空");

        if (excludePaths == null || excludePaths.isEmpty()) {
            return false;
        }

        for (String pattern : excludePaths) {
            if (isPatternMatch(path, pattern)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 检查路径是否与模式匹配
     *
     * @param path    要检查的路径
     * @param pattern Ant风格的路径模式
     * @return 如果匹配返回true，否则返回false
     */
    public static boolean isPatternMatch(String path, String pattern) {
        Assert.hasText(path, "路径不能为空");
        Assert.hasText(pattern, "模式不能为空");

        return pathMatcher.match(pattern, path);
    }

    /**
     * 获取请求的路径（不包含上下文路径和查询参数）
     *
     * @param request HTTP请求对象
     * @return 处理后的请求路径
     */
    public static String getRequestPath(HttpServletRequest request) {
        Assert.notNull(request, "HttpServletRequest不能为null");

        // 获取上下文路径
        String contextPath = request.getContextPath();
        // 获取请求URI（包含上下文路径）
        String requestUri = request.getRequestURI();

        // 移除上下文路径
        if (requestUri.startsWith(contextPath)) {
            String path = requestUri.substring(contextPath.length());
            // 确保路径以"/"开头
            return path.startsWith("/") ? path : "/" + path;
        }

        return requestUri;
    }

    /**
     * 获取请求的完整路径（包含上下文路径）
     *
     * @param request HTTP请求对象
     * @return 完整请求路径
     */
    public static String getFullRequestPath(HttpServletRequest request) {
        Assert.notNull(request, "HttpServletRequest不能为null");

        String requestUri = request.getRequestURI();
        String queryString = request.getQueryString();

        // 如果有查询参数，拼接完整路径
        if (Objects.nonNull(queryString) && !queryString.isEmpty()) {
            return requestUri + "?" + queryString;
        }

        return requestUri;
    }
}